package com.github.yoojia.flow.devices;

import com.github.yoojia.flow.Context;
import com.github.yoojia.flow.Event;
import com.github.yoojia.flow.PiConfig;
import com.github.yoojia.flow.VirtualDevice;
import com.parkingwang.lang.data.Config;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.github.yoojia.flow.util.ConfigKit.checkRequired;

/**
 * @author 陈小锅 (yoojiachen@gmail.com)
 * @since 1.0.0
 */
public abstract class VirtualDigitInputDevice extends VirtualDevice {

    private static final String TAG = VirtualDigitInputDevice.class.getSimpleName();
    private static final Logger LOGGER = LoggerFactory.getLogger(TAG);

    private final GpioPinListenerDigital mStateListener = (this::handleStateChanged);

    @Override
    public void onInit( Context context,  Config configs) throws Exception {
        super.onInit(context, configs);
        checkRequired(configs, PiConfig.NAME_PIN_ADDRESS, TAG);
        checkRequired(configs, PiConfig.NAME_PULL_STATE, TAG);

        final int address = configs.getInt(PiConfig.NAME_PIN_ADDRESS);
        final String state = configs.getString(PiConfig.NAME_PULL_STATE).toUpperCase();
        LOGGER.info("Init InputDigitDevice: uuid={}, address={}, listenState={}", getAddress(), address, state);

        final GpioPinDigitalInput input = GpioFactory
                    .getInstance()
                    .provisionDigitalInputPin(
                            RaspiPin.getPinByAddress(address),
                            getPullState(state));
        if (input == null) {
            throw new IllegalStateException("Failed to bind Input Pin: " + address);
        }
        // 监控开关状态变化
        input.addListener(mStateListener);
    }

    @Override
    public Event handleEvent(Context context, Event request) {
        // 输入信号型开关不接受事件控制
        throw new UnsupportedOperationException(traceableMessage("Method onInterceptEvent(..) is not supported by default!"));
    }

    @Override
    public void onStart() {
        // nop
    }

    @Override
    public void onStop() {
        // nop
    }

    protected abstract void handleStateChanged(GpioPinDigitalStateChangeEvent state);

    ////

    private static PinPullResistance getPullState(String state){
        switch (state){
            default:
            case PiConfig.STATE_PULLUP: return PinPullResistance.PULL_UP;
            case PiConfig.STATE_PULLDOWN: return PinPullResistance.PULL_DOWN;
            case PiConfig.STATE_PULLOFF: return PinPullResistance.OFF;
        }
    }

}
